/* 使用线程特有数据实现线程安全的strerror()函数 */
#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#define MAX_ERROR_LEN 256

static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t strerror_key;

static void destructor(void *buf)
{
    free(buf); /* 释放内存 */
}

static void create_key(void)
{
    /* 创建一个键(key)，并且绑定键的解构函数 */
    if(pthread_key_create(&strerror_key, destructor)) {
        pthread_exit(NULL);
    }
}

/* 对strerror函数重写，使其变成一个线程安全函数 */
static char *my_strerror(int errnum)
{
    char *buf;

    /* 创建一个键（只执行一次create_key) */
    if (pthread_once(&once, create_key)) {
        pthread_exit(NULL);
    }

    /* 获取 */
    buf = (char *)pthread_getspecific(strerror_key);
    if (buf == NULL) { /* 首次调用my_strerror函数，则需给调用线程分配线程四有数据 */
        buf = malloc(MAX_ERROR_LEN); /* 分配内存 */
        if (buf == NULL) {
            pthread_exit(NULL);
        }
        /* 保存缓冲区地质，与键、线程关联起来 */
        if (pthread_setspecific(strerror_key, buf)) {
            pthread_exit(NULL);
        }
    }

    /* 调用strerror函数 */
    if (errnum < 0 || errnum >= _sys_nerr || NULL == _sys_errlist[errnum]) {
        snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", errnum);
    } else {
        strncpy(buf, _sys_errlist[errnum], MAX_ERROR_LEN);
        buf[MAX_ERROR_LEN - 1] = '\0'; /* 终止字符 */
    }

    return buf;
}